﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

using Styx;
using Styx.Common;
using Styx.CommonBot;

using Styx.Helpers;


using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;

using Styx.CommonBot.Routines;
using Styx.CommonBot.Coroutines;

using Styx.TreeSharp;

using CommonBehaviors.Actions;
using System.Windows.Media;

namespace KittyDru
{

    internal static class Spells
    {
        #region Basic Variables
        private static LocalPlayer Me { get { return Styx.StyxWoW.Me; } }
        private static WoWUnit MyTarget { get { return Me.GotTarget ? Me.CurrentTarget : null; } }

        public static string LastCast = null;
        #endregion

        // 5.4 Patch
        #region Spells by name

        public static string Rake { get { return WoWSpell.FromId(1822).Name; } } // Глубокая рана
        public static string Rip { get { return WoWSpell.FromId(1079).Name; } } // Разорвать
        public static string Mangle { get { return WoWSpell.FromId(33917).Name; } } // Увечье - Требует облик медведя с 6.0.2
        public static string Thrash { get { return WoWSpell.FromId(106830).Name; } } // Взбучка
        public static string Shred { get { return WoWSpell.FromId(5221).Name; } } // Полоснуть
        public static string Swipe { get { return WoWSpell.FromId(106785).Name; } } // Размар добавлено в 6.0.2
        public static string FaerieFire { get { return WoWSpell.FromId(770).Name; } } // Волшебный огонь


        public static string HealingTouch { get { return WoWSpell.FromId(5185).Name; } } // Целительное прикосновение


        public static List<string> Common = new List<string>() {
            Rake,
            Rip,
            Mangle,
            Thrash,
            Shred,
            Swipe,
            FaerieFire
        };

        #region Buffs spells
        //public static string MarkOfWild { get { return WoWSpell.FromId(102046).Name; }} // Знак дикой природы удалено в 6.0.2
        public static string MarkOfWild { get { return WoWSpell.FromId(1126).Name; } } // Знак дикой природы добавлено в 6.0.2

        public static List<string> Buffs = new List<string>() {
            MarkOfWild
        };
        #endregion

        #region CD spells
        public static string SavageRoar { get { return WoWSpell.FromId(52610).Name; } } // Дикий рев
        public static string TigersFury { get { return WoWSpell.FromId(5217).Name; } } // Тигриное неистовство

        //public static string Berserk { get { return WoWSpell.FromId(106952).Name; } } // Берсерк удалено в 6.0.2
        public static string Berserk { get { return WoWSpell.FromId(106951).Name; } } // Берсерк добавлено в 6.0.2

        public static string IncarnationKingoftheJungle { get { return WoWSpell.FromId(102543).Name; } } // Перевоплощение: Король джунглей
        public static string Dash { get { return WoWSpell.FromId(1850).Name; } } // Волшебный огонь
        public static string WildCharge { get { return WoWSpell.FromId(102401).Name; } } // Стремительный рывок
        

        public static List<string> CDs = new List<string>() {
            SavageRoar,
            TigersFury,
            Berserk,
            IncarnationKingoftheJungle,
            Dash,
            WildCharge
        };
        #endregion

        #region Finishers spells
        public static string FerociousBite { get { return WoWSpell.FromId(22568).Name; } } // Свирепый укус

        public static List<string> Finishers = new List<string>() {
            FerociousBite
        };
        #endregion


        #region Procs spells
        public static string Clearcasting { get { return WoWSpell.FromId(135700).Name; } } // Знамение Ясности 
        public static string PredatorySwiftness { get { return WoWSpell.FromId(16974).Name; } } // Стремительность хищника

        public static List<string> Procs = new List<string>() {
            Clearcasting,
            PredatorySwiftness
        };
        #endregion

        //public static string Swipe { get { return WoWSpell.FromId(62078).Name; } } // Размар удалено в 6.0.2

        #region Forms spells
        public static string FormCat { get { return WoWSpell.FromId(768).Name; } } // Форма кота
        public static string TravelForm { get { return WoWSpell.FromId(783).Name; } } // Походная форма
        public static string BearForm { get { return WoWSpell.FromId(5487).Name; } } // Форма медведя

        public static List<string> Forms = new List<string>() {
            FormCat,
            TravelForm,
            BearForm
        };
        #endregion

        #region BloodLast
        public static string Heroism { get { return WoWSpell.FromId(32182).Name; } } // Героизм - Шаман - Альянс
        public static string Bloodlust { get { return WoWSpell.FromId(2825).Name; } } //  Жажда крови - Шаман - Орда
        public static string AncientHysteria { get { return WoWSpell.FromId(90355).Name; } } //  Древняя истерия - Охотник - Гончая Недр
        public static string TimeWarp { get { return WoWSpell.FromId(80353).Name; } } //  Искажение времени - Маги

        public static List<string> HeroismSpells = new List<string>() {
            Heroism,
            Bloodlust,
            AncientHysteria,
            TimeWarp
        };
        #endregion


        //public static string WeakenedArmor { get { return WoWSpell.FromId(113746).Name; } } // Ослабленная броня удалено в 6.0.2


        #region Interrupt spells
        //public static string SkullBash { get { return WoWSpell.FromId(80965).Name; } } // Лобовая атака удалено в 6.0.2
        public static string SkullBash { get { return WoWSpell.FromId(106839).Name; } } // Лобовая атака добавлено в 6.0.2

        public static string MightyBash { get { return WoWSpell.FromId(5211).Name; } } // Мощное оглушение

        //public static string Typhoon { get { return WoWSpell.FromId(62078).Name; } } // Тайфун  удалено в 6.0.2
        public static string Typhoon { get { return WoWSpell.FromId(132469).Name; } } // Тайфун добавлено в 6.0.2

        public static List<string> Interrupts = new List<string>() {
            SkullBash,
            MightyBash,
            Typhoon
        };
        #endregion


        public static Dictionary<string, int> EnergyCost = new Dictionary<string, int>() 
        {
            {Rake,              35},
            {Rip,               30},
            {SavageRoar,        25},
            {Thrash,            50},
            {Shred,             40},
            {FerociousBite,     25},
            {Swipe,             45},
        };




        #endregion;

        #region Cast Spell methods

        #region Spell Distance Wrappers
        public static async Task<bool> CastMeleeSpell(string Spell, string Mes)
        {
            if (MyTarget.IsWithinMeleeRange && Me.IsFacing(MyTarget) && MyTarget.InLineOfSpellSight && await Spells.SpellCast(Spell, Mes)) return true;
            return false;
        }
        public static async Task<bool> CastMeleeSpell(string Spell)
        {
            if (MyTarget.IsWithinMeleeRange && Me.IsFacing(MyTarget) && MyTarget.InLineOfSpellSight && await Spells.SpellCast(Spell)) return true;
            return false;
        }

        public static async Task<bool> CastRangeSpell(string Spell, double Distance)
        {
            if (MyTarget.Distance <= Distance && Me.IsFacing(MyTarget) && MyTarget.InLineOfSpellSight && await Spells.SpellCast(Spell)) return true;
            return false;
        }
        #endregion

        #region Getting Spell Data
        public static int SpellCDLeft(string sName) {
            return SpellManager.Spells[sName].CooldownTimeLeft.Seconds;
        }
        #endregion

        #region Cast Spells
        public static async Task<bool> BuffSelf(string spell)
        {
            return await SpellCast(spell, StyxWoW.Me);
        }
        public static async Task<bool> SpellCast(string spell)
        {
            if (spell == null) return false;
            if (Me.GotTarget)
            {
                if (await SpellCast(spell, StyxWoW.Me.CurrentTarget))
                {
                    LastCast = spell;
                    return true;
                }
            }
            return false;
        }
        public static async Task<bool> SpellCast(string spell, string Mes)
        {
            if (Me.GotTarget)
            {
                if (await SpellCast(spell, StyxWoW.Me.CurrentTarget, Mes))
                {
                    LastCast = spell;
                    return true;
                }
            }
            return false;
        }

        public static async Task<bool> SpellCast(string spell, WoWUnit target)
        {
            if (await SpellCast(spell, target, null))
            {
                LastCast = spell;
                return true;
            }
            return false;
        }


        public static async Task<bool> SpellCast(string spell, WoWUnit target, string Mes)
        {
            if (Styx.CommonBot.SpellManager.GlobalCooldown) return false;
            if (!SpellManager.CanCast(spell, target, true)) return false;

            decimal energyCost = 0;

            if(EnergyCost.ContainsKey(spell))
            {
                energyCost = (decimal)EnergyCost[spell];
                if (Me.HasAura(Berserk)) energyCost = Math.Ceiling(energyCost / 2);
                
                if (Me.CurrentEnergy < energyCost)
                {
                    /*Utilities.log("NOT {0}({2} - {3}) on {1}", spell, target.Name == Me.Name ? "Me" : target.SafeName,
                        energyCost.ToString(), Me.CurrentEnergy.ToString());*/
                    return false;
                }
            }


            // Cast spell, return false if it fails to cast
            if (!SpellManager.Cast(spell, target))
            {
                Utilities.log(getLogColor(spell), "!Failed! {0} ({2} - {3}) on {1}", spell, target.Name == Me.Name ? "Me" : target.SafeName,
                    energyCost.ToString(), Me.CurrentEnergy.ToString());
                return false;
            }

            LastCast = spell;

            Utilities.log(getLogColor(spell), "{0} ({2} - {3}) on {1} {4}", spell, target.Name == Me.Name ? "Me" : target.SafeName,
                energyCost.ToString(), Me.CurrentEnergy.ToString(), (Mes != null ? Mes : ""));

            // Wait for lag
            await CommonCoroutines.SleepForLagDuration();

            return true;
        }

        private static Color getLogColor(string spell)
        {
            if (Common.Contains(spell)) return Colors.LightGreen;
            else if (CDs.Contains(spell)) return Colors.Pink;
            else if (Finishers.Contains(spell)) return Colors.Red;
            else if (Interrupts.Contains(spell)) return Colors.Yellow;
            else if (Buffs.Contains(spell)) return Colors.MediumPurple;
            else if (HeroismSpells.Contains(spell)) return Colors.Indigo;
            else if (Forms.Contains(spell)) return Colors.LightSkyBlue;
            return Colors.Blue;
        }
        #endregion

        #endregion

        #region Buffs
        private static readonly Stopwatch timerBuffs = new Stopwatch();

        public static async Task<bool> doBuffs()
        {
            if (!timerBuffs.IsRunning)
            {
                timerBuffs.Start();
                await MarkofWild();
            } else if (timerBuffs.ElapsedMilliseconds < 60 * 10000) return false;
            timerBuffs.Reset();

            //Utilities.log("Precombat Buffs - Buffs");
            return await MarkofWild();
        }

        private static async Task<bool> MarkofWild()
        {

            if (!Me.HasAura(Spells.MarkOfWild))
            {
                Utilities.log("Precombat Buffs - MarkofWild");
                return await BuffSelf(Spells.MarkOfWild);
            }

            return false;
        }
        #endregion


        public static float SpellDistance(this WoWUnit unit, WoWUnit target = null)
        {
            // abort if mob null
            if (unit == null)
                return 0;

            // optional arg implying Me, then make sure not Mob also
            if (target == null)
                target = StyxWoW.Me;

            if (target.IsMe)
            {
                target = unit;
                unit = StyxWoW.Me;
            }

            float dist = target.Location.Distance(unit.Location) - target.CombatReach;
            return Math.Max(0, dist);
        }

    }
}
